package nl.vu.few.ibivu.biomodels.shared;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Embedded;

import nl.vu.few.ibivu.biomodels.client.ui.cytoscapeweb.CytoscapeWebDataField;
import nl.vu.few.ibivu.biomodels.client.ui.cytoscapeweb.CytoscapeWebLayout;
import nl.vu.few.ibivu.biomodels.client.ui.cytoscapeweb.CytoscapeWebNetworkModel;
import nl.vu.few.ibivu.biomodels.client.ui.cytoscapeweb.CytoscapeWebNetworkModelEdge;
import nl.vu.few.ibivu.biomodels.client.ui.cytoscapeweb.CytoscapeWebNetworkModelNode;
import nl.vu.few.ibivu.biomodels.client.ui.cytoscapeweb.CytoscapeWebPoint;
import nl.vu.few.ibivu.biomodels.client.ui.cytoscapeweb.CytoscapeWebPresetLayout;
import nl.vu.few.ibivu.biomodels.shared.uniprot.UniprotEntity;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Indexed;
import com.googlecode.objectify.annotation.Unindexed;

@SuppressWarnings("serial")
public class PetrifierModelData implements Serializable {
	private @Unindexed @Embedded ArrayList<PetrifierArc> edges = new ArrayList<PetrifierArc>();
	private @Unindexed @Embedded ArrayList<PetrifierNode> nodes = new ArrayList<PetrifierNode>();
	private @Unindexed @Embedded ArrayList<PetrifierDataField> nodeFields = new ArrayList<PetrifierDataField>();
	private @Unindexed @Embedded ArrayList<PetrifierDataField> edgeFields = new ArrayList<PetrifierDataField>();
	private @Unindexed @Embedded ArrayList<PetrifierPoint> points = new ArrayList<PetrifierPoint>();
	private @Unindexed boolean fitToScreen;
	private @Indexed List<Key<UniprotEntity>> uniprotEntities;
	
	public PetrifierModelData() {
		uniprotEntities = new ArrayList<Key<UniprotEntity>>();
	}

	public List<Key<UniprotEntity>> getUniprotEntities() {
		return uniprotEntities;
	}
	
	/**
	 * NOTE: This method is not meant to be executed on server side.
	 * @param networkModel
	 */
	public void setNetworkModel(CytoscapeWebNetworkModel networkModel) {
		uniprotEntities.clear();
		
		this.nodes.clear();
		JsArray<CytoscapeWebNetworkModelNode> nodes = networkModel.getNodes();
		for (int i = 0; i < nodes.length(); i++) {
			PetrifierNode pNode = new PetrifierNode(nodes.get(i));
			String value = pNode.getUniprotId();
			if (value != null) {
					uniprotEntities.add(new Key<UniprotEntity>(UniprotEntity.class, value));
			}
			this.nodes.add(pNode);
		}
		
		this.edges.clear();
		JsArray<CytoscapeWebNetworkModelEdge> edges = networkModel.getEdges();
		for (int i = 0; i < edges.length(); i++) {
			this.edges.add(new PetrifierArc(edges.get(i)));
		}
		
		this.nodeFields.clear();
		JsArray<CytoscapeWebDataField> fields = networkModel.getNodesDataSchema();
		for (int i = 0; i < fields.length(); i++) {
			this.nodeFields.add(new PetrifierDataField(fields.get(i)));
		}
		
		this.edgeFields.clear();
		fields = networkModel.getEdgesDataSchema();
		for (int i = 0; i < fields.length(); i++) {
			this.edgeFields.add(new PetrifierDataField(fields.get(i)));
		}
	}
	
	private static final native <E extends JavaScriptObject> JsArray<E> createArray() /*-{
		return new $wnd.Array();
	}-*/;
	
	
	public CytoscapeWebNetworkModel getNetworkModel() {
		JsArray<CytoscapeWebNetworkModelEdge> nmEdges = createArray();
		for (PetrifierArc edge : edges) {
			nmEdges.push(edge.cytoscapeWebNetworkModelEdge());
		}
		
		JsArray<CytoscapeWebNetworkModelNode> nmNodes = createArray();
		for (PetrifierNode node : nodes) {
			nmNodes.push(node.cytoscapeWebNetworkModelNode());
		}
		
		JsArray<CytoscapeWebDataField> nmNodesFields = createArray();
		for (PetrifierDataField field : nodeFields) {
			nmNodesFields.push(field.cytoscapeWebDataField());
		}
		
		JsArray<CytoscapeWebDataField> nmEdgesFields = createArray();
		for (PetrifierDataField field : edgeFields) {
			nmEdgesFields.push(field.cytoscapeWebDataField());
		}
		
		return CytoscapeWebNetworkModel.create(nmNodes, nmEdges, nmNodesFields, nmEdgesFields);
	}

	/**
	 * NOTE: This method is not meant to be executed on server side.
	 * @param layout
	 */
	public void setLayout(CytoscapeWebPresetLayout layout) {
		this.points.clear();
		JsArray<CytoscapeWebPoint> points = layout.getPoints();
		for (int i = 0; i < points.length(); i++) {
			this.points.add(new PetrifierPoint(points.get(i)));
		}
		this.fitToScreen = layout.isFitToScreen();
	}
	
	public CytoscapeWebLayout getLayout() {
		JsArray<CytoscapeWebPoint> lPoints = createArray();
		for (PetrifierPoint point : points) {
			lPoints.push(point.cytoscapeWebPoint());
		}
		return CytoscapeWebPresetLayout.create(fitToScreen, lPoints);
	}
	
	public boolean isFitToScreen() {
		return fitToScreen;
	}

	public void setFitToScreen(boolean fitToScreen) {
		this.fitToScreen = fitToScreen;
	}

	public ArrayList<PetrifierArc> getEdges() {
		return edges;
	}

	public ArrayList<PetrifierNode> getNodes() {
		return nodes;
	}
	
	public void setEdges(ArrayList<PetrifierArc> edges) {
		this.edges = edges;
	}

	public void setNodes(ArrayList<PetrifierNode> nodes) {
		this.nodes = nodes;
	}
}
